﻿using Core;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace g_gongjianta.battle.fsm
{
    public abstract class AbstractSkillState : AbstractFsmState
    {
        protected TblSkill.Conf conf;

        protected readonly ESkillLinkType[] EAttackArr =
        {
            ESkillLinkType.Attack
        };

        protected readonly ESkillLinkType[] EMoveArr =
        {
            ESkillLinkType.Move,
        };

        protected List<Action> funcList = new();
        protected List<Action> delayList = new();

        protected TriggerWholeRecord wholeRecord = new();

        private readonly List<LinkNode> nodes = new();

        protected int frameCount;
        protected int startFrame;


        protected SenseComponent mSense;
        protected SkillComponent mSkill;
        protected TblSkill mTable;

        protected override void Init()
        {
            var unit = character as Unit;
            Debug.Assert(unit != null);

            mSense = unit.Get<SenseComponent>();
            mSkill = unit.Get<SkillComponent>();
            mTable = character.TblSkill;
        }

        public override void Enter()
        {
            startFrame = SysTime.FrameCount;
            frameCount = 0;

            wholeRecord.Clear();

            InitOperateNode(conf);

            CheckFunc(false);

            if (wholeRecord.IsTriggered && wholeRecord.State != 0)
            {
                if (wholeRecord.IsTriggered)
                {
                    Root.Switch(wholeRecord.State, wholeRecord.SkillId);
                }
            }
            else
            {
                Confirm();
            }
        }

        protected virtual void Confirm() { }

        public override void Exit()
        {
            wholeRecord.Clear();
            skillSrl = 0;
            nodes.ForEach(c => c.Dispose());
            nodes.Clear();
        }

        public override void Update()
        {
            wholeRecord.Clear();

            frameCount = SysTime.FrameCount - startFrame;

            CheckFunc(true);

            var lowerSrl = wholeRecord.Srl;

            if (wholeRecord.IsTriggered && wholeRecord.State != 0 && lowerSrl == wholeRecord.Srl)
            {
                Root.Switch(wholeRecord.State, wholeRecord.SkillId);
            }
        }

        protected void CheckFunc(bool with_default)
        {
            bool flag = false;
            for (int i = 0; i < funcList.Count; ++i)
            {
                funcList[i].Invoke();

                if (wholeRecord.IsTriggered)
                {
                    flag = true;
                    break;
                }
            }

            if (flag == false && with_default)
            {
                for (int i = 0; i < delayList.Count; ++i)
                {
                    delayList[i].Invoke();

                    if (wholeRecord.IsTriggered)
                    {
                        break;
                    }
                }
            }
        }

        private void InitOperateNode(TblSkill.Conf conf)
        {
            if (conf == null)
            {
                return;
            }

            nodes.ForEach(c => c.Dispose());
            nodes.Clear();

            if (conf.Links != null)
            {
                for (int i = 0; i < conf.Links.Length; i++)
                {
                    Add2Node(conf, conf.Links[i]);
                }
            }
        }

        private void Add2Node(TblSkill.Conf conf, TblSkill.Link link)
        {
            if (link.EndFrame < link.StartFrame || link.EndFrame >= conf.Duration || link.EndFrame == 0)
            {
                link.EndFrame = conf.Duration - 1;
            }

            var node = G.Factory.Create<LinkNode>();
            node.Init(link, mSense);

            nodes.Add(node);
        }

        protected void ResetCheckNode()
        {
            InitOperateNode(conf);
        }

        protected int PollingMoveSkill()
        {
            return PollingTriggeredSkill(EMoveArr);
        }

        protected int PollingAttackSkill()
        {
            return PollingTriggeredSkill(EAttackArr);
        }

        protected int PollingTriggeredSkill(ESkillLinkType[] type_arr)
        {
            LinkNode triggerNode = null;
            int triggerSkillID = 0;
            for (int i = 0; i < nodes.Count; i++)
            {
                var node = nodes[i];
                bool r = false;
                for (int j = 0; j < type_arr.Length; j++)
                {
                    if ((int)node.Link.Type == (int)type_arr[j])
                    {
                        r = true;
                        break;
                    }
                }

                if (r == false)
                {
                    continue;
                }

                var skill = mSkill.Get(skillSrl);
                if (skill != null)
                {
                    node.Check(skill.FrameCount);
                }
                else
                {
                    node.Check(frameCount);
                }

                if (node.IsTrigger)
                {
                    triggerNode = node;
                    triggerSkillID = node.Link.SkillId;
                    break;
                }
            }

            if (triggerNode != null)
            {
                triggerNode.Dispose();
                nodes.Remove(triggerNode);
            }

            var skillConf = mTable.Find(triggerSkillID);
            return skillConf != null ? triggerSkillID : 0;
        }
    }
}